package com.starsea.book.ui.book.read

import android.app.Application
import android.content.Intent
import android.net.Uri
import android.text.TextUtils
import androidx.collection.arrayMapOf
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.MutableLiveData
import com.google.gson.Gson
import com.starsea.book.base.BaseViewModel
import com.starsea.book.constant.AppConst
import com.starsea.book.constant.AppLog
import com.starsea.book.constant.BookType
import com.starsea.book.constant.EventBus
import com.starsea.book.data.appDb
import com.starsea.book.data.entities.Book
import com.starsea.book.data.entities.BookChapter
import com.starsea.book.data.entities.BookProgress
import com.starsea.book.exception.NoStackTraceException
import com.starsea.book.help.AppWebDav
import com.starsea.book.help.book.BookHelp
import com.starsea.book.help.book.ContentProcessor
import com.starsea.book.help.book.isLocal
import com.starsea.book.help.book.removeType
import com.starsea.book.help.config.AppConfig
import com.starsea.book.help.coroutine.Coroutine
import com.starsea.book.help.http.newCallResponseBody
import com.starsea.book.help.http.okHttpClient
import com.starsea.book.help.http.postJson
import com.starsea.book.help.http.text
import com.starsea.book.model.ImageProvider
import com.starsea.book.model.ReadAloud
import com.starsea.book.model.ReadBook
import com.starsea.book.model.localBook.LocalBook
import com.starsea.book.model.webBook.WebBook
import com.starsea.book.service.BaseReadAloudService
import com.starsea.book.ui.book.read.page.entities.TextChapter
import com.starsea.book.ui.book.searchContent.SearchResult
import com.starsea.book.ui.newpage.entity.BaseEntity
import com.starsea.book.ui.newpage.entity.BookInfoEntity
import com.starsea.book.ui.newpage.entity.BookSectionListEntity
import com.starsea.book.ui.newpage.utils.gsonList
import com.starsea.book.ui.newpage.utils.gsonNormal
import com.starsea.book.utils.*
import com.starsea.book.R
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream

/**
 * 阅读界面数据处理
 */
class ReadBookViewModel(application: Application) : BaseViewModel(application) {
    //    val permissionDenialLiveData = MutableLiveData<Int>()
//    var isInitFinish = false
//    var searchContentQuery = ""
//    var searchResultList: List<SearchResult>? = null
//    var searchResultIndex: Int = 0
//    private var changeSourceCoroutine: Coroutine<*>? = null
//
//    init {
//        AppConfig.detectClickArea()
//    }
//
//    /**
//     * 初始化
//     */
//    fun initData(intent: Intent, success: (() -> Unit)? = null) {
//        execute {
//            ReadBook.inBookshelf = intent.getBooleanExtra("inBookshelf", true)
//            ReadBook.tocChanged = intent.getBooleanExtra("tocChanged", false)
//            ReadBook.chapterChanged = intent.getBooleanExtra("chapterChanged", false)
//            val bookUrl = intent.getStringExtra("bookUrl")
//
//            com.blankj.utilcode.util.LogUtils.e(">>>> ", "bookUrl = " + bookUrl)
//            val book = when {
////                bookUrl.isNullOrEmpty() -> appDb.bookDao.lastReadBook
//                bookUrl.isNullOrEmpty() -> {
//                    return@execute
//                }
//
//                else -> appDb.bookDao.getBook(bookUrl)
//            } ?: ReadBook.book
//            when {
//                book != null -> initBook(book, bookUrl)
//                else -> ReadBook.upMsg(context.getString(R.string.no_book))
//            }
//        }.onSuccess {
//            success?.invoke()
//        }.onError {
//            val msg = "初始化数据失败\n${it.localizedMessage}"
//            ReadBook.upMsg(msg)
//            AppLog.put(msg, it)
//        }.onFinally {
//            ReadBook.saveRead()
//        }
//    }
//
//    private fun initBook(book: Book, bookUrl: String) {
//
//        LogUtils.e(">>>> ", "readbook = " + book.toString())
//
////        val isSameBook = ReadBook.book?.bookUrl == book.bookUrl
//        val isSameBook = ReadBook.book?.bookUrl == bookUrl
//        LogUtils.e(">>>> ", "isSameBook = $isSameBook")
//
//        if (isSameBook) {
//            ReadBook.upData(book)
//        } else {
//            ReadBook.resetData(book)
//        }
//        isInitFinish = true
//
//        LogUtils.e(">>>> ", "chapterSize = " + ReadBook.chapterSize)
//
//        LogUtils.e(">>>> ", "book.isLocal = " + book.isLocal)
//        LogUtils.e(
//            ">>>> ",
//            "LocalBook = " + (LocalBook.getLastModified(book)
//                .getOrDefault(0L) > book.latestChapterTime)
//        )
//
//        if (ReadBook.chapterSize == 0) {
//            LogUtils.e(">>>> ", "tocUrl = " + book.tocUrl)
//            if (book.tocUrl.isEmpty()) {
//                loadBookInfo(book)
//            } else {
//                loadChapterList(book)
//            }
//        } else if (book.isLocal
////            && LocalBook.getLastModified(book).getOrDefault(0L) > book.latestChapterTime
//        ) {
//            loadChapterList(book)
//        } else if (isSameBook) {
//            if (ReadBook.curTextChapter != null) {
//                ReadBook.callBack?.upContent(resetPageOffset = false)
//            } else {
//                ReadBook.loadContent(resetPageOffset = true)
//            }
//            checkLocalBookFileExist(book)
//        } else {
//            if (ReadBook.durChapterIndex > ReadBook.chapterSize - 1) {
//                ReadBook.durChapterIndex = ReadBook.chapterSize - 1
//            }
//
//            LogUtils.e(">>>", ">>> loadContent")
//            ReadBook.loadContent(resetPageOffset = false)
//
//            checkLocalBookFileExist(book)
//        }
//
//        if (ReadBook.chapterChanged) {
//            // 有章节跳转不同步阅读进度
//            ReadBook.chapterChanged = false
//        } else if (!isSameBook || !BaseReadAloudService.isRun) {
//            syncBookProgress(book)
//        }
//
//        if (!book.isLocal && ReadBook.bookSource == null) {
//            autoChangeSource(book.name, book.author)
//            return
//        }
//    }
//
//    private fun checkLocalBookFileExist(book: Book) {
//        if (book.isLocal) {
//            execute {
//                LocalBook.getBookInputStream(book)
//            }.onError {
//                if (it is FileNotFoundException) {
//                    permissionDenialLiveData.postValue(0)
//                }
//            }
//        }
//    }
//
//    /**
//     * 加载详情页
//     */
//    private fun loadBookInfo(book: Book) {
//        if (book.isLocal) {
//            loadChapterList(book)
//        } else {
//
//            com.blankj.utilcode.util.LogUtils.e(">>>> ", " bookid = " + book.bookUrl)
//            execute {
//                okHttpClient.newCallResponseBody {
//                    url(AppConst.BASE_URL.plus("front-api/book/book_read_detail?bookId=${book.bookUrl}"))
//                        .post("".toRequestBody())
//                }.text().let {
//
//                    LogUtils.e(">>>>> ", it)
//                    val entity: BaseEntity<BookInfoEntity> =
//                        it.gsonNormal(BookInfoEntity::class.java)
//
//                    if (entity.status != 200) {
//                        context.toastOnUi(entity.msg)
//                    } else {
//                        val book = Book(
//                            name = entity.data!!.bookTitle.toString(),
//                            author = entity.data!!.authorName.toString(),
//                            kind = "",
//                            bookUrl = entity.data!!.bookId.toString(),
//                            origin = "",
//                            originName = "",
//                            type = 1,
//                            wordCount = entity.data!!.wordCount.toString(),
//                            latestChapterTitle = "",
//                            coverUrl = entity.data!!.bookCover.toString(),
//                            intro = entity.data!!.bookDesc.toString(),
//                            tocUrl = "",
//                            originOrder = 0,
//                            variable = ""
//                        )
//
//                        com.blankj.utilcode.util.LogUtils.e(">>>>   ReadBook.book = ${ReadBook.book}")
//                        ReadBook.inBookshelf = entity.data!!.bookShelfFlag == 1
//                        saveBook(book) {
//                            if (ReadBook.book == null) {
//                                ReadBook.book = book
//                                book.durChapterTitle = entity.data!!.sectionTitle
//                                initBook(book, book.bookUrl)
//                            } else {
//                                book.durChapterTitle = entity.data!!.sectionTitle
//                                loadChapterList(book)
//                            }
//                        }
//                    }
//                }
//
////            throw NoStackTraceException("未找到书籍")
//            }.onError {
//                AppLog.put(it.localizedMessage, it)
//                context.toastOnUi(it.localizedMessage)
//            }
//
//
////            ReadBook.bookSource?.let { source ->
////                WebBook.getBookInfo(viewModelScope, source, book, canReName = false)
////                    .onSuccess {
////                        loadChapterList(book)
////                    }.onError {
////                        ReadBook.upMsg("详情页出错: ${it.localizedMessage}")
////                    }
////            }
//        }
//    }
//
//    fun saveBook(book: Book?, success: (() -> Unit)? = null) {
//
//        LogUtils.e(">>>> ", " saveBook = " + book.toString())
//
//        book ?: return
//
//        execute {
//            if (book.order == 0) {
//                book.order = appDb.bookDao.minOrder - 1
//            }
////            appDb.bookDao.getBook(book.name, book.author)?.let {
//            appDb.bookDao.getBook(book.bookUrl)?.let {
//
//                com.blankj.utilcode.util.LogUtils.e(">>>> durChapterPos = ${it.durChapterPos}")
//                com.blankj.utilcode.util.LogUtils.e(">>>> durChapterTitle = ${it.durChapterTitle}")
//                if (!TextUtils.isEmpty(it.durChapterTitle)) {
//                    book.durChapterPos = it.durChapterPos
//                    book.durChapterTitle = it.durChapterTitle
//                }
//
//            }
//            book.save()
//            if (ReadBook.book?.name == book.name && ReadBook.book?.author == book.author) {
//                ReadBook.book = book
//            }
//            LogUtils.e(">>>> ", " book.save()")
//        }.onSuccess {
//
//            LogUtils.e(">>>> ", "onSuccess")
//            success?.invoke()
//        }
//    }
//
//    /**
//     * 加载目录
//     */
//    fun loadChapterList(book: Book) {
//        if (book.isLocal) {
//            execute {
//                LocalBook.getChapterList(book).let {
//                    book.latestChapterTime = System.currentTimeMillis()
//                    appDb.bookChapterDao.delByBook(book.bookUrl)
//                    appDb.bookChapterDao.insert(*it.toTypedArray())
//                    appDb.bookDao.update(book)
//                    ReadBook.chapterSize = it.size
//                    ReadBook.upMsg(null)
//                    ReadBook.loadContent(resetPageOffset = true)
//                }
//            }.onError {
//                when (it) {
//                    is SecurityException, is FileNotFoundException -> {
//                        permissionDenialLiveData.postValue(1)
//                    }
//
//                    else -> {
//                        AppLog.put("LoadTocError:${it.localizedMessage}", it)
//                        ReadBook.upMsg("LoadTocError:${it.localizedMessage}")
//                    }
//                }
//            }
//        } else {
//
//            execute {
//                okHttpClient.newCallResponseBody {
//                    url(AppConst.BASE_URL.plus("front-api/book/book_section_list?bookId=${book.bookUrl}"))
//                        .post("".toRequestBody())
//                }.text().let {
//
//                    LogUtils.e(">>>>> 章节列表", it)
//                    val entity: BaseEntity<MutableList<BookSectionListEntity>> =
//                        it.gsonList(BookSectionListEntity::class.java)
//
//                    val chapterList: MutableList<BookChapter> = arrayListOf()
//                    entity.data!!.forEachIndexed { index, bookSectionListEntity ->
//                        val bookChapter = BookChapter()
//                        bookChapter.title = bookSectionListEntity.sectionTitle.toString()
//                        bookChapter.url = bookSectionListEntity.sectionId.toString()
////                    是否免费 0:免费 1:收费
////                        bookChapter.isVip = bookSectionListEntity.isFree == 0
//                        bookChapter.isPay = bookSectionListEntity.isFree == 0
//                        bookChapter.bookUrl = book.bookUrl
//                        bookChapter.index = index
//                        chapterList.add(bookChapter)
//                    }
////                    chapterListData.postValue(chapterList)
////                    bookSectionListResult.postValue(entity)
//
//                    val oldBook = book.copy()
//
//                    if (oldBook.bookUrl == book.bookUrl) {
//                        appDb.bookDao.update(book)
//                    } else {
//                        appDb.bookDao.insert(book)
//                        BookHelp.updateCacheFolder(oldBook, book)
//                    }
//                    appDb.bookChapterDao.delByBook(oldBook.bookUrl)
//                    appDb.bookChapterDao.insert(*chapterList.toTypedArray())
//                    ReadBook.chapterSize = chapterList.size
//                    ReadBook.upMsg(null)
//                    ReadBook.loadContent(resetPageOffset = true)
//                }
//            }.onError {
//                context.toastOnUi(it.localizedMessage ?: "ERROR")
//            }
////            ReadBook.bookSource?.let {
////                val oldBook = book.copy()
////                WebBook.getChapterList(viewModelScope, it, book, true)
////                    .onSuccess(IO) { cList ->
////                        if (oldBook.bookUrl == book.bookUrl) {
////                            appDb.bookDao.update(book)
////                        } else {
////                            appDb.bookDao.insert(book)
////                            BookHelp.updateCacheFolder(oldBook, book)
////                        }
////                        appDb.bookChapterDao.delByBook(oldBook.bookUrl)
////                        appDb.bookChapterDao.insert(*cList.toTypedArray())
////                        ReadBook.chapterSize = cList.size
////                        ReadBook.upMsg(null)
////                        ReadBook.loadContent(resetPageOffset = true)
////                    }.onError {
////                        ReadBook.upMsg(context.getString(R.string.error_load_toc))
////                    }
////            }
//        }
//    }
//
//    /**
//     * 同步进度
//     */
//    fun syncBookProgress(
//        book: Book,
//        alertSync: ((progress: BookProgress) -> Unit)? = null
//    ) {
//        if (!AppConfig.syncBookProgress) return
//        execute {
//            AppWebDav.getBookProgress(book)
//                ?: throw NoStackTraceException("没有进度")
//        }.onError {
//            AppLog.put("拉取阅读进度失败《${book.name}》", it)
//        }.onSuccess { progress ->
//            if (progress.durChapterIndex < book.durChapterIndex ||
//                (progress.durChapterIndex == book.durChapterIndex
//                        && progress.durChapterPos < book.durChapterPos)
//            ) {
//                alertSync?.invoke(progress)
//            } else {
//                ReadBook.setProgress(progress)
//                AppLog.put("自动同步阅读进度成功《${book.name}》 ${progress.durChapterTitle}")
//            }
//        }
//
//    }
//
//    /**
//     * 换源
//     */
//    fun changeTo(book: Book, toc: List<BookChapter>) {
//        changeSourceCoroutine?.cancel()
//        changeSourceCoroutine = execute {
//            ReadBook.upMsg(context.getString(R.string.loading))
//            ReadBook.book?.migrateTo(book, toc)
//            book.removeType(BookType.updateError)
//            ReadBook.book?.delete()
//            appDb.bookDao.insert(book)
//            appDb.bookChapterDao.insert(*toc.toTypedArray())
//            ReadBook.resetData(book)
//            ReadBook.upMsg(null)
//            ReadBook.loadContent(resetPageOffset = true)
//        }.onError {
//            context.toastOnUi("换源失败\n${it.localizedMessage}")
//            ReadBook.upMsg(null)
//        }.onFinally {
//            postEvent(EventBus.SOURCE_CHANGED, book.bookUrl)
//        }
//    }
//
//    /**
//     * 自动换源
//     */
//    private fun autoChangeSource(name: String, author: String) {
//        if (!AppConfig.autoChangeSource) return
//        execute {
//            val sources = appDb.bookSourceDao.allTextEnabled
//
//            LogUtils.e(">>> ", "sources = " + sources.toString())
//
//            sources.forEach { source ->
//                WebBook.preciseSearchAwait(this, source, name, author).getOrNull()?.let { book ->
//                    if (book.tocUrl.isEmpty()) {
//                        WebBook.getBookInfoAwait(source, book)
//                    }
//                    val toc = WebBook.getChapterListAwait(source, book).getOrThrow()
//                    val chapter = toc.getOrElse(book.durChapterIndex) {
//                        toc.last()
//                    }
//                    val nextChapter = toc.getOrElse(chapter.index) {
//                        toc.first()
//                    }
//                    kotlin.runCatching {
//                        WebBook.getContentAwait(
//                            bookSource = source,
//                            book = book,
//                            bookChapter = chapter,
//                            nextChapterUrl = nextChapter.url
//                        )
//                        changeTo(book, toc)
//                        return@execute
//                    }
//                }
//            }
//            throw NoStackTraceException("没有合适书源")
//        }.onStart {
//            ReadBook.upMsg(context.getString(R.string.source_auto_changing))
//        }.onError {
//            AppLog.put("自动换源失败\n${it.localizedMessage}", it)
//            context.toastOnUi("自动换源失败\n${it.localizedMessage}")
//        }.onFinally {
//            ReadBook.upMsg(null)
//        }
//    }
//
//    fun openChapter(index: Int, durChapterPos: Int = 0, success: (() -> Unit)? = null) {
//        if (index < ReadBook.chapterSize) {
//            ReadBook.clearTextChapter()
//            ReadBook.callBack?.upContent()
//            ReadBook.durChapterIndex = index
//            ReadBook.durChapterPos = durChapterPos
//            ReadBook.saveRead()
//            ReadBook.loadContent(resetPageOffset = true) {
//                success?.invoke()
//            }
//        }
//    }
//
//    fun removeFromBookshelf(success: (() -> Unit)?) {
//        execute {
//            ReadBook.book?.delete()
//        }.onSuccess {
//            success?.invoke()
//        }
//    }
//
//    fun upBookSource(success: (() -> Unit)?) {
//        execute {
//            ReadBook.book?.let { book ->
//                ReadBook.bookSource = appDb.bookSourceDao.getBookSource(book.origin)
//            }
//        }.onSuccess {
//            success?.invoke()
//        }
//    }
//
//    fun refreshContentDur(book: Book) {
//        execute {
//            appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
//                ?.let { chapter ->
//                    BookHelp.delContent(book, chapter)
//                    ReadBook.loadContent(ReadBook.durChapterIndex, resetPageOffset = false)
//                }
//        }
//    }
//
//    fun refreshContentAfter(book: Book) {
//        execute {
//            appDb.bookChapterDao.getChapterList(
//                book.bookUrl,
//                ReadBook.durChapterIndex,
//                book.totalChapterNum
//            ).forEach { chapter ->
//                BookHelp.delContent(book, chapter)
//            }
//            ReadBook.loadContent(false)
//        }
//    }
//
//    fun refreshContentAll(book: Book) {
//        execute {
//            BookHelp.clearCache(book)
//            ReadBook.loadContent(false)
//        }
//    }
//
//    /**
//     * 保存内容
//     */
//    fun saveContent(book: Book, content: String) {
//        execute {
//            appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
//                ?.let { chapter ->
//                    BookHelp.saveText(book, chapter, content)
//                    ReadBook.loadContent(ReadBook.durChapterIndex, resetPageOffset = false)
//                }
//        }
//    }
//
//    /**
//     * 反转内容
//     */
//    fun reverseContent(book: Book) {
//        execute {
//            val chapter = appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
//                ?: return@execute
//            val content = BookHelp.getContent(book, chapter) ?: return@execute
//            val stringBuilder = StringBuilder()
//            content.toStringArray().forEach {
//                stringBuilder.insert(0, it)
//            }
//            BookHelp.saveText(book, chapter, stringBuilder.toString())
//            ReadBook.loadContent(ReadBook.durChapterIndex, resetPageOffset = false)
//        }
//    }
//
//    /**
//     * 内容搜索跳转
//     */
//    fun searchResultPositions(
//        textChapter: TextChapter,
//        searchResult: SearchResult
//    ): Array<Int> {
//        // calculate search result's pageIndex
//        val pages = textChapter.pages
//        val content = textChapter.getContent()
//        val queryLength = searchContentQuery.length
//
//        var count = 0
//        var index = content.indexOf(searchContentQuery)
//        while (count != searchResult.resultCountWithinChapter) {
//            index = content.indexOf(searchContentQuery, index + queryLength)
//            count += 1
//        }
//        val contentPosition = index
//        var pageIndex = 0
//        var length = pages[pageIndex].text.length
//        while (length < contentPosition && pageIndex + 1 < pages.size) {
//            pageIndex += 1
//            length += pages[pageIndex].text.length
//        }
//
//        // calculate search result's lineIndex
//        val currentPage = pages[pageIndex]
//        val curTextLines = currentPage.lines
//        var lineIndex = 0
//        var curLine = curTextLines[lineIndex]
//        length = length - currentPage.text.length + curLine.text.length
//        if (curLine.isParagraphEnd) length++
//        while (length < contentPosition && lineIndex + 1 < curTextLines.size) {
//            lineIndex += 1
//            curLine = curTextLines[lineIndex]
//            length += curLine.text.length
//            if (curLine.isParagraphEnd) length++
//        }
//
//        // charIndex
//        val currentLine = currentPage.lines[lineIndex]
//        var curLineLength = currentLine.text.length
//        if (currentLine.isParagraphEnd) curLineLength++
//        length -= curLineLength
//
//        val charIndex = contentPosition - length
//        var addLine = 0
//        var charIndex2 = 0
//        // change line
//        if ((charIndex + queryLength) > curLineLength) {
//            addLine = 1
//            charIndex2 = charIndex + queryLength - curLineLength - 1
//        }
//        // changePage
//        if ((lineIndex + addLine + 1) > currentPage.lines.size) {
//            addLine = -1
//            charIndex2 = charIndex + queryLength - curLineLength - 1
//        }
//        return arrayOf(pageIndex, lineIndex, charIndex, addLine, charIndex2)
//    }
//
//    /**
//     * 翻转删除重复标题
//     */
//    fun reverseRemoveSameTitle() {
//        execute {
//            val book = ReadBook.book ?: return@execute
//            val textChapter = ReadBook.curTextChapter ?: return@execute
//            BookHelp.setRemoveSameTitle(
//                book, textChapter.chapter, !textChapter.sameTitleRemoved
//            )
//            ReadBook.loadContent(ReadBook.durChapterIndex)
//        }
//    }
//
//    /**
//     * 刷新图片
//     */
//    fun refreshImage(src: String) {
//        execute {
//            ReadBook.book?.let { book ->
//                val vFile = BookHelp.getImage(book, src)
//                ImageProvider.bitmapLruCache.remove(vFile.absolutePath)
//                vFile.delete()
//            }
//        }.onFinally {
//            ReadBook.loadContent(false)
//        }
//    }
//
//    /**
//     * 保存图片
//     */
//    @Suppress("BlockingMethodInNonBlockingContext")
//    fun saveImage(src: String?, uri: Uri) {
//        src ?: return
//        val book = ReadBook.book ?: return
//        execute {
//            val image = BookHelp.getImage(book, src)
//            FileInputStream(image).use { input ->
//                if (uri.isContentScheme()) {
//                    DocumentFile.fromTreeUri(context, uri)?.let { doc ->
//                        val imageDoc = DocumentUtils.createFileIfNotExist(doc, image.name)!!
//                        context.contentResolver.openOutputStream(imageDoc.uri)!!.use { output ->
//                            input.copyTo(output)
//                        }
//                    }
//                } else {
//                    val dir = File(uri.path ?: uri.toString())
//                    val file = FileUtils.createFileIfNotExist(dir, image.name)
//                    FileOutputStream(file).use { output ->
//                        input.copyTo(output)
//                    }
//                }
//            }
//        }.onError {
//            AppLog.put("保存图片出错\n${it.localizedMessage}", it)
//            context.toastOnUi("保存图片出错\n${it.localizedMessage}")
//        }
//    }
//
//    /**
//     * 替换规则变化
//     */
//    fun replaceRuleChanged() {
//        execute {
//            ReadBook.book?.let {
//                ContentProcessor.get(it.name, it.origin).upReplaceRules()
//                ReadBook.loadContent(resetPageOffset = false)
//            }
//        }
//    }
//
//    fun disableSource() {
//        execute {
//            ReadBook.bookSource?.let {
//                it.enabled = false
//                appDb.bookSourceDao.update(it)
//            }
//        }
//    }
//
//    override fun onCleared() {
//        super.onCleared()
//        if (BaseReadAloudService.pause) {
//            ReadAloud.stop(context)
//        }
//    }
//
//    val addReadHistoryResult = MutableLiveData<BaseEntity<Boolean>>()
//    val addSherfResult = MutableLiveData<BaseEntity<Any>>()
//
//    fun addReadHistory(
//        bookId: String,
//        createTime: String,
//        leaveTime: String,
//        sectionId: String,
//        sectionTitle: String
//    ) {
//        val map: MutableMap<String, String> = arrayMapOf()
//        map["bookId"] = bookId.toString()
//        map["createTime"] = createTime
//        map["leaveTime"] = leaveTime
//        map["sectionId"] = sectionId
//        map["sectionTitle"] = sectionTitle
//        val json = Gson().toJson(map)
//
//        LogUtils.e(">>> ", "json = " + json)
//        execute {
////            LogUtils.e(">>> ", "json = " + json)
//            okHttpClient.newCallResponseBody {
////                LogUtils.e(">>> ", "json = " + json)
//                url(AppConst.BASE_URL.plus("front-api/book-read/addReadBookHistory"))
//                    .postJson(json)
//
//            }.text().let {
//                LogUtils.e(">>>", ">>.${it}")
////                val entity: BaseEntity<Boolean> =
////                    it.gsonNormal(Boolean::class.java)
////                addReadHistoryResult.postValue(entity)
//            }
//        }.onError {
//            context.toastOnUi(it.localizedMessage ?: "ERROR")
//        }
//    }
//
//    fun addToShelf(
//        bookId: String,
//        sectionId: String = "",
//        sectionTitle: String = ""
//    ) {
//
//        var url = AppConst.BASE_URL.plus("front-api/book-shelf/favorBook?bookId=${bookId}")
//        LogUtils.e(">>>>> ", "sectionId = " + sectionId)
//        LogUtils.e(">>>>> ", "sectionTitle = " + sectionTitle)
//        if (!TextUtils.isEmpty(sectionId)) {
//            url = url.plus("&sectionId=${sectionId}&sectionTitle=${sectionTitle}")
//        }
//
//        LogUtils.e(">>>>> ", "url = " + url)
//
//        execute {
////            LogUtils.e(">>> ", "json = " + json)
//            okHttpClient.newCallResponseBody {
////                LogUtils.e(">>> ", "json = " + json)
//                url(url)
//                    .post("".toRequestBody())
////                    .postJson(json)
//
//            }.text().let {
//                LogUtils.e(">>>", ">>.${it}")
//                val entity: BaseEntity<Any> =
//                    it.gsonNormal(Any::class.java)
//                addSherfResult.postValue(entity)
//            }
//        }.onError {
//            context.toastOnUi(it.localizedMessage ?: "ERROR")
//        }
//    }
//
    val permissionDenialLiveData = MutableLiveData<Int>()
    var isInitFinish = false
    var searchContentQuery = ""
    var searchResultList: List<SearchResult>? = null
    var searchResultIndex: Int = 0
    private var changeSourceCoroutine: Coroutine<*>? = null

    init {
        AppConfig.detectClickArea()
    }

    /**
     * 初始化
     */
    fun initData(intent: Intent, success: (() -> Unit)? = null) {
        execute {
            ReadBook.inBookshelf = intent.getBooleanExtra("inBookshelf", false)
            ReadBook.tocChanged = intent.getBooleanExtra("tocChanged", false)
            ReadBook.chapterChanged = intent.getBooleanExtra("chapterChanged", false)
            val bookUrl = intent.getStringExtra("bookUrl")

            com.blankj.utilcode.util.LogUtils.e(">>>> ", "bookUrl = " + bookUrl)
            val book = when {
//                bookUrl.isNullOrEmpty() -> appDb.bookDao.lastReadBook
                bookUrl.isNullOrEmpty() -> {
                    return@execute
                }

                else -> appDb.bookDao.getBook(bookUrl)
            } ?: ReadBook.book
            when {
                book != null -> {
                    com.blankj.utilcode.util.LogUtils.e(">>>>> book != null ${System.currentTimeMillis()}")

                    initBook(book, bookUrl)
                }
//                else -> ReadBook.upMsg(context.getString(R.string.no_book))
//                com.blankj.utilcode.util.LogUtils.e(">>>>> ${System.currentTimeMillis()}")
                else -> {
                    com.blankj.utilcode.util.LogUtils.e(">>>>> else  ${System.currentTimeMillis()}")
                    val books = Book(bookUrl = bookUrl)
                    loadBookInfo(books)
                }
            }
        }.onSuccess {
            success?.invoke()
        }.onError {
            val msg = "初始化数据失败\n${it.localizedMessage}"
            ReadBook.upMsg(msg)
            AppLog.put(msg, it)
        }.onFinally {
            ReadBook.saveRead()
        }
    }

    private fun initBook(book: Book, bookUrl: String) {

        LogUtils.e(">>>> ", "readbook = " + book.toString())
//        val isSameBook = ReadBook.book?.bookUrl == book.bookUrl
        val isSameBook = ReadBook.book?.bookUrl == bookUrl
        LogUtils.e(">>>> ", "isSameBook = $isSameBook")

//        if (isSameBook) {
//            ReadBook.upData(book)
//        } else {
        ReadBook.resetData(book)
//        }

        isInitFinish = true

        LogUtils.e(">>>> ", "chapterSize = " + ReadBook.chapterSize)

        LogUtils.e(">>>> ", "book.isLocal = " + book.isLocal)
        LogUtils.e(
            ">>>> ",
            "LocalBook = " + (LocalBook.getLastModified(book)
                .getOrDefault(0L) > book.latestChapterTime)
        )

        if (ReadBook.chapterSize == 0) {
            LogUtils.e(">>>> ", "tocUrl = " + book.tocUrl)
            if (book.tocUrl.isEmpty()) {
                loadBookInfo(book)
            } else {
                loadChapterList(book)
            }
        } else if (book.isLocal
//            && LocalBook.getLastModified(book).getOrDefault(0L) > book.latestChapterTime
        ) {
            loadChapterList(book)
        } else if (isSameBook) {
            if (ReadBook.curTextChapter != null) {
                ReadBook.callBack?.upContent(resetPageOffset = false)
            } else {
                ReadBook.loadContent(resetPageOffset = false)
            }
            checkLocalBookFileExist(book)
        } else {
            if (ReadBook.durChapterIndex > ReadBook.chapterSize - 1) {
                ReadBook.durChapterIndex = ReadBook.chapterSize - 1
            }

            LogUtils.e(">>>", ">>> loadContent")
            ReadBook.loadContent(resetPageOffset = false)

            checkLocalBookFileExist(book)
        }

        com.blankj.utilcode.util.LogUtils.e(
            ">>>",
            ">>> ReadBook.chapterChanged = ${ReadBook.chapterChanged}"
        )
        if (ReadBook.chapterChanged) {
            // 有章节跳转不同步阅读进度
            ReadBook.chapterChanged = false
        } else if (!isSameBook || !BaseReadAloudService.isRun) {
            com.blankj.utilcode.util.LogUtils.e(">>>", "syncBookProgress")
            syncBookProgress(book)
        }

        if (!book.isLocal && ReadBook.bookSource == null) {
            autoChangeSource(book.name, book.author)
            return
        }
    }

    private fun checkLocalBookFileExist(book: Book) {
        if (book.isLocal) {
            execute {
                LocalBook.getBookInputStream(book)
            }.onError {
                if (it is FileNotFoundException) {
                    permissionDenialLiveData.postValue(0)
                }
            }
        }
    }

    /**
     * 加载详情页
     */
    private fun loadBookInfo(book: Book) {

        com.blankj.utilcode.util.LogUtils.e(">>> loadBookInfo book = ${book.isLocal}")
        if (book.isLocal) {
            loadChapterList(book)
        } else {
            com.blankj.utilcode.util.LogUtils.e(">>>> ", " bookid = " + book.bookUrl)
            execute {
                okHttpClient.newCallResponseBody {
                    url(AppConst.BASE_URL.plus("front-api/book/book_read_detail?bookId=${book.bookUrl}"))
                        .post("".toRequestBody())
                }.text().let {

                    com.blankj.utilcode.util.LogUtils.e(">>>>> ", it)
                    val entity: BaseEntity<BookInfoEntity> =
                        it.gsonNormal(BookInfoEntity::class.java)

                    if (entity.status != 200) {
                        context.toastOnUi(entity.msg)
                    } else {
                        val book = Book(
                            name = entity.data!!.bookTitle.toString(),
                            author = entity.data!!.authorName.toString(),
                            kind = "",
                            bookUrl = entity.data!!.bookId.toString(),
                            origin = "",
                            originName = "",
                            type = 1,
                            wordCount = entity.data!!.wordCount.toString(),
                            latestChapterTitle = "",
                            coverUrl = entity.data!!.bookCover.toString(),
                            intro = entity.data!!.bookDesc.toString(),
                            tocUrl = "",
                            originOrder = 0,
                            variable = "",
                            durChapterTitle = entity.data!!.sectionTitle
                        )

                        com.blankj.utilcode.util.LogUtils.e(">>>>   ReadBook.book = ${ReadBook.book}")
                        ReadBook.inBookshelf = entity.data!!.bookShelfFlag == 1
                        saveBook(book) {
                            if (ReadBook.book == null) {
                                ReadBook.book = book
                                book.durChapterTitle = entity.data!!.sectionTitle
                                initBook(book, book.bookUrl)
                            } else {
                                book.durChapterTitle = entity.data!!.sectionTitle
                                loadChapterList(book)
                            }
                        }
                    }
                }

//            throw NoStackTraceException("未找到书籍")
            }.onError {
                AppLog.put(it.localizedMessage, it)
                context.toastOnUi(it.localizedMessage)
            }
        }
    }

    fun saveBook(book: Book?, success: (() -> Unit)? = null) {

        LogUtils.e(">>>> ", " saveBook = " + book.toString())

        book ?: return

        execute {
            if (book.order == 0) {
                book.order = appDb.bookDao.minOrder - 1
            }
//            appDb.bookDao.getBook(book.name, book.author)?.let {
            appDb.bookDao.getBook(book.bookUrl)?.let {

                com.blankj.utilcode.util.LogUtils.e(">>>> durChapterPos = ${it.durChapterPos}")
                com.blankj.utilcode.util.LogUtils.e(">>>> durChapterTitle = ${it.durChapterTitle}")
                if (!TextUtils.isEmpty(it.durChapterTitle)) {
                    book.durChapterPos = it.durChapterPos
                    book.durChapterTitle = it.durChapterTitle
                }

            }
            book.save()
            if (ReadBook.book?.name == book.name && ReadBook.book?.author == book.author) {
                ReadBook.book = book
            }
            LogUtils.e(">>>> ", " book.save()")
        }.onSuccess {

            LogUtils.e(">>>> ", "onSuccess")
            success?.invoke()
        }
    }

    /**
     * 加载目录
     */
    fun loadChapterList(book: Book) {
        if (book.isLocal) {
            execute {
                LocalBook.getChapterList(book).let {
                    book.latestChapterTime = System.currentTimeMillis()
                    appDb.bookChapterDao.delByBook(book.bookUrl)
                    appDb.bookChapterDao.insert(*it.toTypedArray())
                    appDb.bookDao.update(book)
                    ReadBook.chapterSize = it.size
                    ReadBook.upMsg(null)
                    ReadBook.loadContent(resetPageOffset = false)
                }
            }.onError {
                when (it) {
                    is SecurityException, is FileNotFoundException -> {
                        permissionDenialLiveData.postValue(1)
                    }

                    else -> {
                        AppLog.put("LoadTocError:${it.localizedMessage}", it)
                        ReadBook.upMsg("LoadTocError:${it.localizedMessage}")
                    }
                }
            }
        } else {
            com.blankj.utilcode.util.LogUtils.e(">>>>> book.bookUrl = ${book.bookUrl}")
            execute {
                okHttpClient.newCallResponseBody {
                    url(AppConst.BASE_URL.plus("front-api/book-read/book_section_list?bookId=${book.bookUrl}"))
                        .post("".toRequestBody())
                }.text().let {

                    LogUtils.e(">>>>> 章节列表", it)
                    val entity: BaseEntity<MutableList<BookSectionListEntity>> =
                        it.gsonList(BookSectionListEntity::class.java)

                    val chapterList: MutableList<BookChapter> = arrayListOf()
                    entity.data!!.forEachIndexed { index, bookSectionListEntity ->
                        val bookChapter = BookChapter()
                        bookChapter.title = bookSectionListEntity.sectionTitle.toString()
                        bookChapter.url = bookSectionListEntity.sectionId.toString()
//                    是否免费 0:免费 1:收费
                        bookChapter.isVip = bookSectionListEntity.isFree == 1
                        bookChapter.isPay = bookSectionListEntity.isFree == 0
                        bookChapter.bookUrl = book.bookUrl
                        bookChapter.index = index
                        chapterList.add(bookChapter)
                    }

                    com.blankj.utilcode.util.LogUtils.e(">>>>> book.durChapterTitle = ${book.durChapterTitle}")
                    val index =
                        entity.data!!.indexOfFirst { it.sectionTitle == book.durChapterTitle }

                    com.blankj.utilcode.util.LogUtils.e(">>>> index = $index")

//                    book.durChapterIndex = if (index == -1) 0 else index
                    book.durChapterIndex =
                        if (ReadBook.book != null) {
                            if (index > ReadBook.durChapterIndex) {
                                index
                            } else {
                                ReadBook.durChapterIndex
                            }
                        } else {
                            if (index == -1) 0 else index
                        }

//                    ReadBook.durChapterIndex = if (index == -1) 0 else index
                    ReadBook.durChapterIndex =
                        if (ReadBook.book != null) {
                            if (index > ReadBook.durChapterIndex) {
                                index
                            } else {
                                ReadBook.durChapterIndex
                            }
                        } else {
                            if (index == -1) 0 else index
                        }


                    val oldBook = book.copy()

                    oldBook.durChapterIndex = if (index == -1) 0 else index

                    if (oldBook.bookUrl == book.bookUrl) {
                        appDb.bookDao.update(book)
                    } else {
                        appDb.bookDao.insert(book)
                        BookHelp.updateCacheFolder(oldBook, book)
                    }
                    appDb.bookChapterDao.delByBook(oldBook.bookUrl)
                    appDb.bookChapterDao.insert(*chapterList.toTypedArray())
                    ReadBook.chapterSize = chapterList.size
                    ReadBook.upMsg(null)
                    ReadBook.loadContent(resetPageOffset = false)
                }
            }.onError {
                context.toastOnUi(it.localizedMessage ?: "ERROR")
            }
        }
    }

    /**
     * 同步进度
     */
    fun syncBookProgress(
        book: Book,
        alertSync: ((progress: BookProgress) -> Unit)? = null
    ) {
        if (!AppConfig.syncBookProgress) return
        execute {
            okHttpClient.newCallResponseBody {
//                url(AppConst.BASE_URL.plus("front-api/book-read/book_section_list?bookId=${book.bookUrl}"))
                url(AppConst.BASE_URL.plus("front-api/book/book_section_list?bookId=${book.bookUrl}"))
                    .post("".toRequestBody())
            }.text().let {

                com.blankj.utilcode.util.LogUtils.e(">>>>blankj  ${it.toString()}")

                val entitySectionList: BaseEntity<MutableList<BookSectionListEntity>> =
                    it.gsonList(BookSectionListEntity::class.java)
                execute {
                    okHttpClient.newCallResponseBody {
                        url(AppConst.BASE_URL.plus("front-api/book/book_read_detail?bookId=${book.bookUrl}"))
                            .post("".toRequestBody())
                    }.text().let {


                        val entity: BaseEntity<BookInfoEntity> =
                            it.gsonNormal(BookInfoEntity::class.java)

                        if (entity.status != 200) {
                            context.toastOnUi(entity.msg)
                        } else {
                            val index =
                                entitySectionList.data!!.indexOfFirst { it.sectionId == entity.data!!.sectionId }
//                                20

                            com.blankj.utilcode.util.LogUtils.e(">>>>> index = ${index}")
                            com.blankj.utilcode.util.LogUtils.e(">>>>> book.durChapterIndex = ${book.durChapterIndex}")

                            if (index < book.durChapterIndex
                            ) {
//                                alertSync?.invoke(progress)
                            } else {
                                book.durChapterIndex = index

                                com.blankj.utilcode.util.LogUtils.e(">>>> BookProgress = ${index}")

                                val bookProgress: BookProgress = BookProgress(
                                    book
                                )

                                ReadBook.setProgress(bookProgress)
                                AppLog.put("自动同步阅读进度成功《${book.name}》 ${bookProgress.durChapterTitle}")
                            }

                        }
                    }

//            throw NoStackTraceException("未找到书籍")
                }.onError {
                    AppLog.put(it.localizedMessage, it)
                    context.toastOnUi(it.localizedMessage)
                }

//                val entity: BaseEntity<MutableList<BookSectionListEntity>> =
//                    it.gsonList(BookSectionListEntity::class.java)
//                if (!entity.data!!.isEmpty()) {
//
//                    com.blankj.utilcode.util.LogUtils.e(">>>> book = ${book.durChapterIndex}" )
//
//                    book.durChapterIndex = 30
//                    book.durChapterTitle =
//                    val bookProgress: BookProgress = BookProgress(
//                        book
//                    )
//
//                    ReadBook.setProgress(bookProgress)
//                }


            }
        }.onError {
            context.toastOnUi(it.localizedMessage ?: "ERROR")
        }

//                .onError {
//            AppLog.put("拉取阅读进度失败《${book.name}》", it)
//        }.onSuccess { progress ->
//            if (progress.durChapterIndex < book.durChapterIndex ||
//                (progress.durChapterIndex == book.durChapterIndex
//                        && progress.durChapterPos < book.durChapterPos)
//            ) {
//                alertSync?.invoke(progress)
//            } else {
//                ReadBook.setProgress(progress)
//                AppLog.put("自动同步阅读进度成功《${book.name}》 ${progress.durChapterTitle}")
//            }
//        }

    }

    /**
     * 换源
     */
    fun changeTo(book: Book, toc: List<BookChapter>) {
        changeSourceCoroutine?.cancel()
        changeSourceCoroutine = execute {
            ReadBook.upMsg(context.getString(R.string.loading))
            ReadBook.book?.migrateTo(book, toc)
            book.removeType(BookType.updateError)
            ReadBook.book?.delete()
            appDb.bookDao.insert(book)
            appDb.bookChapterDao.insert(*toc.toTypedArray())
            ReadBook.resetData(book)
            ReadBook.upMsg(null)
            ReadBook.loadContent(resetPageOffset = true)
        }.onError {
            context.toastOnUi("换源失败\n${it.localizedMessage}")
            ReadBook.upMsg(null)
        }.onFinally {
            postEvent(EventBus.SOURCE_CHANGED, book.bookUrl)
        }
    }

    /**
     * 自动换源
     */
    private fun autoChangeSource(name: String, author: String) {
        if (!AppConfig.autoChangeSource) return
        execute {
            val sources = appDb.bookSourceDao.allTextEnabled

            LogUtils.e(">>> ", "sources = " + sources.toString())

            sources.forEach { source ->
                WebBook.preciseSearchAwait(this, source, name, author).getOrNull()?.let { book ->
                    if (book.tocUrl.isEmpty()) {
                        WebBook.getBookInfoAwait(source, book)
                    }
                    val toc = WebBook.getChapterListAwait(source, book).getOrThrow()
                    val chapter = toc.getOrElse(book.durChapterIndex) {
                        toc.last()
                    }
                    val nextChapter = toc.getOrElse(chapter.index) {
                        toc.first()
                    }
                    kotlin.runCatching {
                        WebBook.getContentAwait(
                            bookSource = source,
                            book = book,
                            bookChapter = chapter,
                            nextChapterUrl = nextChapter.url
                        )
                        changeTo(book, toc)
                        return@execute
                    }
                }
            }
            throw NoStackTraceException("没有合适书源")
        }.onStart {
            ReadBook.upMsg(context.getString(R.string.source_auto_changing))
        }.onError {
            AppLog.put("自动换源失败\n${it.localizedMessage}", it)
            context.toastOnUi("自动换源失败\n${it.localizedMessage}")
        }.onFinally {
            ReadBook.upMsg(null)
        }
    }

    fun openChapter(index: Int, durChapterPos: Int = 0, success: (() -> Unit)? = null) {
        if (index < ReadBook.chapterSize) {
            ReadBook.clearTextChapter()
            ReadBook.callBack?.upContent()
            ReadBook.durChapterIndex = index
            ReadBook.durChapterPos = durChapterPos
            ReadBook.saveRead()
            ReadBook.loadContent(resetPageOffset = true) {
                success?.invoke()
            }
        }
    }

    fun removeFromBookshelf(success: (() -> Unit)?) {
        execute {
            ReadBook.book?.delete()
        }.onSuccess {
            success?.invoke()
        }
    }

    fun upBookSource(success: (() -> Unit)?) {
        execute {
            ReadBook.book?.let { book ->
                ReadBook.bookSource = appDb.bookSourceDao.getBookSource(book.origin)
            }
        }.onSuccess {
            success?.invoke()
        }
    }

    fun refreshContentDur(book: Book) {
        execute {
            appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
                ?.let { chapter ->
                    BookHelp.delContent(book, chapter)
                    ReadBook.loadContent(ReadBook.durChapterIndex, resetPageOffset = false)
                }
        }
    }

    fun refreshContentAfter(book: Book) {
        execute {
            appDb.bookChapterDao.getChapterList(
                book.bookUrl,
                ReadBook.durChapterIndex,
                book.totalChapterNum
            ).forEach { chapter ->
                BookHelp.delContent(book, chapter)
            }
            ReadBook.loadContent(false)
        }
    }

    fun refreshContentAll(book: Book) {
        execute {
            BookHelp.clearCache(book)
            ReadBook.loadContent(false)
        }
    }

    /**
     * 保存内容
     */
    fun saveContent(book: Book, content: String) {
        execute {
            appDb.bookChapterDao.getChapter(book.bookUrl, ReadBook.durChapterIndex)
                ?.let { chapter ->
                    BookHelp.saveText(book, chapter, content)
                    ReadBook.loadContent(ReadBook.durChapterIndex, resetPageOffset = false)
                }
        }
    }


    /**
     * 内容搜索跳转
     */
    fun searchResultPositions(
        textChapter: TextChapter,
        searchResult: SearchResult
    ): Array<Int> {
        // calculate search result's pageIndex
        val pages = textChapter.pages
        val content = textChapter.getContent()
        val queryLength = searchContentQuery.length

        var count = 0
        var index = content.indexOf(searchContentQuery)
        while (count != searchResult.resultCountWithinChapter) {
            index = content.indexOf(searchContentQuery, index + queryLength)
            count += 1
        }
        val contentPosition = index
        var pageIndex = 0
        var length = pages[pageIndex].text.length
        while (length < contentPosition && pageIndex + 1 < pages.size) {
            pageIndex += 1
            length += pages[pageIndex].text.length
        }

        // calculate search result's lineIndex
        val currentPage = pages[pageIndex]
        val curTextLines = currentPage.lines
        var lineIndex = 0
        var curLine = curTextLines[lineIndex]
        length = length - currentPage.text.length + curLine.text.length
        if (curLine.isParagraphEnd) length++
        while (length < contentPosition && lineIndex + 1 < curTextLines.size) {
            lineIndex += 1
            curLine = curTextLines[lineIndex]
            length += curLine.text.length
            if (curLine.isParagraphEnd) length++
        }

        // charIndex
        val currentLine = currentPage.lines[lineIndex]
        var curLineLength = currentLine.text.length
        if (currentLine.isParagraphEnd) curLineLength++
        length -= curLineLength

        val charIndex = contentPosition - length
        var addLine = 0
        var charIndex2 = 0
        // change line
        if ((charIndex + queryLength) > curLineLength) {
            addLine = 1
            charIndex2 = charIndex + queryLength - curLineLength - 1
        }
        // changePage
        if ((lineIndex + addLine + 1) > currentPage.lines.size) {
            addLine = -1
            charIndex2 = charIndex + queryLength - curLineLength - 1
        }
        return arrayOf(pageIndex, lineIndex, charIndex, addLine, charIndex2)
    }

    /**
     * 翻转删除重复标题
     */
    fun reverseRemoveSameTitle() {
        execute {
            val book = ReadBook.book ?: return@execute
            val textChapter = ReadBook.curTextChapter ?: return@execute
            BookHelp.setRemoveSameTitle(
                book, textChapter.chapter, !textChapter.sameTitleRemoved
            )
            ReadBook.loadContent(ReadBook.durChapterIndex)
        }
    }

    /**
     * 刷新图片
     */
    fun refreshImage(src: String) {
        execute {
            ReadBook.book?.let { book ->
                val vFile = BookHelp.getImage(book, src)
                ImageProvider.bitmapLruCache.remove(vFile.absolutePath)
                vFile.delete()
            }
        }.onFinally {
            ReadBook.loadContent(false)
        }
    }

    /**
     * 保存图片
     */
    @Suppress("BlockingMethodInNonBlockingContext")
    fun saveImage(src: String?, uri: Uri) {
        src ?: return
        val book = ReadBook.book ?: return
        execute {
            val image = BookHelp.getImage(book, src)
            FileInputStream(image).use { input ->
                if (uri.isContentScheme()) {
                    DocumentFile.fromTreeUri(context, uri)?.let { doc ->
                        val imageDoc = DocumentUtils.createFileIfNotExist(doc, image.name)!!
                        context.contentResolver.openOutputStream(imageDoc.uri)!!.use { output ->
                            input.copyTo(output)
                        }
                    }
                } else {
                    val dir = File(uri.path ?: uri.toString())
                    val file = FileUtils.createFileIfNotExist(dir, image.name)
                    FileOutputStream(file).use { output ->
                        input.copyTo(output)
                    }
                }
            }
        }.onError {
            AppLog.put("保存图片出错\n${it.localizedMessage}", it)
            context.toastOnUi("保存图片出错\n${it.localizedMessage}")
        }
    }

    /**
     * 替换规则变化
     */
    fun replaceRuleChanged() {
        execute {
            ReadBook.book?.let {
                ContentProcessor.get(it.name, it.origin).upReplaceRules()
                ReadBook.loadContent(resetPageOffset = false)
            }
        }
    }

    fun disableSource() {
        execute {
            ReadBook.bookSource?.let {
                it.enabled = false
                appDb.bookSourceDao.update(it)
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        if (BaseReadAloudService.pause) {
            ReadAloud.stop(context)
        }
    }

    val addReadHistoryResult = MutableLiveData<BaseEntity<Boolean>>()
    val addSherfResult = MutableLiveData<BaseEntity<Any>>()

    fun addReadHistory(
        bookId: String,
        createTime: String,
        leaveTime: String,
        sectionId: String,
        sectionTitle: String,
        createTimeTimestamp: Long,
        leaveTimeTimestamp: Long
    ) {
        val map: MutableMap<String, Any> = arrayMapOf()
        map["bookId"] = bookId.toString()
        map["createTime"] = createTime
        map["leaveTime"] = leaveTime
        map["sectionId"] = sectionId
        map["sectionTitle"] = sectionTitle
        map["createTimeTimestamp"] = createTimeTimestamp
        map["leaveTimeTimestamp"] = leaveTimeTimestamp
        val json = Gson().toJson(map)

        LogUtils.e(">>> ", "json = " + json)
        execute {
//            LogUtils.e(">>> ", "json = " + json)
            okHttpClient.newCallResponseBody {
//                LogUtils.e(">>> ", "json = " + json)
                url(AppConst.BASE_URL.plus("front-api/book-read/addReadBookHistory"))
                    .postJson(json)

            }.text().let {
                LogUtils.e(">>>", ">>.${it}")
//                val entity: BaseEntity<Boolean> =
//                    it.gsonNormal(Boolean::class.java)
//                addReadHistoryResult.postValue(entity)
            }
        }.onError {
            context.toastOnUi(it.localizedMessage ?: "ERROR")
        }
    }

    fun addToShelf(
        bookId: String,
        sectionId: String = "",
        sectionTitle: String = ""
    ) {

        var url =
            AppConst.BASE_URL.plus("front-api/bookShelf/favorBook?bookId=${bookId}")
        LogUtils.e(">>>>> ", "sectionId = " + sectionId)
        LogUtils.e(">>>>> ", "sectionTitle = " + sectionTitle)
        if (!TextUtils.isEmpty(sectionId)) {
            url = url.plus("&sectionId=${sectionId}&sectionTitle=${sectionTitle}")
        }

        LogUtils.e(">>>>> ", "url = " + url)

        execute {
//            LogUtils.e(">>> ", "json = " + json)
            okHttpClient.newCallResponseBody {
//                LogUtils.e(">>> ", "json = " + json)
                url(url)
                    .post("".toRequestBody())
//                    .postJson(json)

            }.text().let {
                LogUtils.e(">>>", ">>.${it}")
                val entity: BaseEntity<Any> =
                    it.gsonNormal(Any::class.java)
                addSherfResult.postValue(entity)
            }
        }.onError {
            context.toastOnUi(it.localizedMessage ?: "ERROR")
        }
    }


    fun advertErrorMsg(
        code: Int, errorMsg: String, version
        : String, phone: String, time: String
    ) {
        val map: MutableMap<String, Any> = arrayMapOf()
        map["code"] = code
        map["errorMsg"] = errorMsg
        map["version"] = version
        map["phone"] = phone
        map["time"] = time
        val json = Gson().toJson(map)
        execute {
            okHttpClient.newCallResponseBody {
                url(AppConst.BASE_URL.plus("front-api/person/testCSJ"))
                    .postJson(json)
            }.text().let {
//                LogUtils.e(">>>> activity ", "it = " + it)
//                val entity: BaseEntity<SignInfoEntity?> =
//                    it.gsonNormalNull(SignInfoEntity::class.java)
//                signInfoResult.postValue(entity)
            }
        }.onError {
            context.toastOnUi(it.localizedMessage ?: "ERROR")
        }

    }
}
